﻿using MathNet.Numerics;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;

namespace nCoV2019_Predict
{
    public partial class Form1 : Form
    {
        int useDay = 5; // 用于拟合数据的天数
        DataHelper dataHelper = new DataHelper();

        public Form1()
        {
            InitializeComponent();
            System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;

            listBoxContry.SelectedIndex = 0;
            labelNow.Text = dataHelper.ParseGlobalNow();
            Run();
            RunBackground();
        }
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Environment.Exit(0);
        }

        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            Run();
        }
        private void numericUpDown1_ValueChanged(object sender, EventArgs e)
        {
            Run();
        }

        private void Run()
        {
            var dataRow = dataHelper.ParseGlobalHistory(listBoxContry.SelectedItem.ToString());
            var data = dataRow.OrderBy(i => i.日期Date).ToList();
            if (data.Last().日期Date == DateTime.Today) data.RemoveAt(data.Count - 1);
            toolStripStatusLabel1.Text = data.Last().日期Date.ToString("yyyy-MM-dd") + $" 之后均为预测数据 The data after {data.Last().日期Date.ToString("yyyy-MM-dd")} is predicted";

            var P = Fit(data);
            Predict(P.Pc, P.Ph, P.Pd, data);

            dataGridView1.DataSource = data;

            chart1.ChartAreas[0].AxisY.Maximum = data.Last().确诊Confirm * 1.1;
            chart1.Series.Clear();
            new List<string> { "确诊Confirm", "治愈Heal", "死亡Dead" }.ForEach(i => Plot(i, data));
        }
        private async void RunBackground()
        {
            var succeed = await dataHelper.DownLoadGlobalHistoryNew();
            if (succeed)
            {
                labelNow.Text = dataHelper.ParseGlobalNow();
                Run();
                toolStripStatusLabel1.Text += ".";
            }
            else
            {
                toolStripStatusLabel1.Text += ".";
            }
        }
        private (double[] Pc, double[] Ph, double[] Pd) Fit(List<DataRaw> data)
        {
            var x = new double[useDay];
            var (yc, yh, yd) = (new double[useDay], new double[useDay], new double[useDay]);
            var dataCount = data.Count - useDay;
            for (int i = 0; i < useDay; i++)
            {
                x[i] = i;
                yc[i] = data[dataCount + i].确诊Confirm;
                yh[i] = data[dataCount + i].治愈Heal;
                yd[i] = data[dataCount + i].死亡Dead;
            }
            var Pc = MathNet.Numerics.Fit.Polynomial(x, yc, 1);
            var Ph = MathNet.Numerics.Fit.Polynomial(x, yh, 1);
            var Pd = MathNet.Numerics.Fit.Polynomial(x, yd, 1);
            return (Pc, Ph, Pd);
        }
        private void Predict(double[] Pc, double[] Ph, double[] Pd, List<DataRaw> data)
        {
            for (int i = useDay; i <= useDay + numericUpDown1.Value; i++)
            {
                data.Add(new DataRaw()
                {
                    日期Date = data.Last().日期Date.AddDays(1),
                    confirm = (int)Math.Ceiling(Polynomial.Evaluate(i, Pc)),
                    heal = (int)Math.Ceiling(Polynomial.Evaluate(i, Ph)),
                    dead = (int)Math.Ceiling(Polynomial.Evaluate(i, Pd))
                });
            }
        }
        private void Plot(string name, List<DataRaw> data)
        {
            Series series = null;
            switch (name)
            {
                case "确诊Confirm":
                    series = new Series() { Name = name, ChartType = SeriesChartType.Point, Color = Color.Blue };
                    data.ForEach(i => series.Points.AddXY(i.日期Date, i.确诊Confirm)); break;
                case "治愈Heal":
                    series = new Series() { Name = name, ChartType = SeriesChartType.Point, Color = Color.Green };
                    data.ForEach(i => series.Points.AddXY(i.日期Date, i.治愈Heal)); break;
                case "死亡Dead":
                    series = new Series() { Name = name, ChartType = SeriesChartType.Point, Color = Color.Red };
                    data.ForEach(i => series.Points.AddXY(i.日期Date, i.死亡Dead)); break;
            }
            chart1.Series.Add(series);
        }
    }
}